﻿
using HarfBuzzSharp;
using LightCAD.MathLib;
using LightCAD.Three;
using System;
using System.Diagnostics;
using System.Diagnostics.Metrics;
using System.Linq;
using System.Reactive.Joins;
using System.Xml.Schema;
using GeometryData = LightCAD.Model.GeometryData;

namespace QdArch
{

    public class RoofAction : ComponentInstance2dAction
    {
        private QdRoofInstance Roof;
        private QdRoofRef rootRef;
        private double topScale = 1;
        private double bottomScale = 1;
        private Vector3 normal = new Vector3(0,0,1);
        private LcParameterSet parameterSet;
        private Vector2 insertPoint;
        private PointInputer PointInputer { get; set; }

        public RoofAction() :base() 
        {
            
        }
        public RoofAction(IDocumentEditor docEditor) : base(docEditor)
        {
            this.commandCtrl.WriteInfo("命令：Roof"); 
        }
        public async void ExecCreate(string[] args = null)
        {
            this.StartCreating();
            var win = (IRoofRefWindow)AppRuntime.UISystem.CreateWindow("RoofRefSelect");
            var result = AppRuntime.UISystem.ShowDialog(win);
            if (result != LcDialogResult.OK)
            {
                return;
            }
            rootRef = ComponentManager.GetCptDef<QdRoofRef>("屋顶", "坡屋顶", win.Uuid );
            if (rootRef == null)
                return;
            Roof = new QdRoofInstance( rootRef);
            Roof.SlabThickness = 400;
            Roof.FasciaDepth = 100;
            Roof.SectionType = 2;
            Roof.Angle = Math.PI/6;
            Roof.Elevation = 0;
            PointInputer = new PointInputer(this.docEditor);
            Insert:
            var result0 = await PointInputer.Execute("请选择插入点");
            if (PointInputer.isCancelled)
            {
                goto End;
            }
            if (result0.ValueX!=null)
            {
                insertPoint = (Vector2)result0.ValueX;
            }
            else
            {
                var opvec = GetOptionVector(result0.Option);
                if (opvec != null)
                {
                    insertPoint = opvec;
                }else
                    goto Insert;
            }
            
            Create:
            Roof.Initilize(this.docRt.Document);
            Roof.Position.Set(insertPoint.X, insertPoint.Y, 0);
            Roof.ResetCache();
            this.docRt.Document.ModelSpace.InsertElement(Roof);
            End:
            this.EndCreating();
        }
        private Vector2 GetOptionVector(string Option)
        {
            if (!string.IsNullOrEmpty(Option))
            {
                var xyz = Option.split(",");
                if (double.TryParse(xyz[0].Trim(), out var pX) && double.TryParse(xyz[1].Trim(), out var pY))
                {
                    return new Vector2(pX, pY);
                }
            }
            return null;
        }
        public override void Draw(SKCanvas canvas, LcElement element, Matrix3 matrix)
        {
            var roof = element as QdRoofInstance;
            // var curves = Roof.ShapeCurves;
            var curves = roof.Curves?.FirstOrDefault().Curve2ds;
            foreach (var curve in curves)
            {
                if (curve is Line2d line)
                {
                    var start = this.vportRt.ConvertWcsToScr(line.Start).ToSKPoint();
                    var end = this.vportRt.ConvertWcsToScr(line.End).ToSKPoint();
                    using (var elePen = new SKPaint { Color = SKColors.Green, IsStroke = true })
                    {
                        canvas.DrawLine(start, end, elePen);
                    }
                }
 
            }
        }
        public override void DrawAuxLines(SKCanvas canvas)
        {
            var mp = this.vportRt.PointerMovedPosition.ToVector2d();
            var wcs_mp = this.vportRt.ConvertScrToWcs(mp);
            var sk_p = this.vportRt.ConvertWcsToScr(wcs_mp).ToSKPoint();
            if (Roof != null)
            {
                var curves = Roof.Curves.FirstOrDefault();
                if (curves == null)
                    return;
                foreach (var curve in curves.Curve2ds)
                {
                    if (curve is Line2d)
                    {
                        var line = curve.Clone().Translate(insertPoint ?? wcs_mp) as Line2d;
                        var start = this.vportRt.ConvertWcsToScr(line.Start).ToSKPoint();
                        var end = this.vportRt.ConvertWcsToScr(line.End).ToSKPoint();
                        using (var elePen = new SKPaint { Color = SKColors.Green, IsStroke = true })
                        {
                            canvas.DrawLine(start, end, elePen);
                        }
                    }
                    else if (curve is Arc2d)
                    {
                        var arc = curve.Clone().Translate(insertPoint ?? wcs_mp) as Arc2d;

                        using (var elePen = new SKPaint { Color = SKColors.Green, IsStroke = true })
                        {
                            Matrix3 matrix = Matrix3.GetTranslate(new Vector2(0, 0));
                            this.vportRt.DrawArc(arc, matrix, canvas, elePen);
                        }
                    }
                }
                
            }
 
        }
        #region Grip
        private string _gripName;
        private Vector2 _position;
        public override ControlGrip[] GetControlGrips(LcElement element)
        {
            var roof = element as QdRoofInstance;
            var grips = new List<ControlGrip>();
            var startPoint = new ControlGrip
            {
                Element = roof,
                Name = "InsertPoint",
                Position = roof.Transform3d.Position.ToVector2()
            };
            grips.Add(startPoint);
            return grips.ToArray();
        }

        public override void SetDragGrip(LcElement element, string gripName, Vector2 position, bool isEnd)
        {
            var roof = element as QdRoofInstance;
            if (!isEnd)
            {
                roof.OnPropertyChangedBefore("Position", null, null);

                _gripName = gripName;
                _position = position;
                roof.Position.Set(position.X, position.Y);
                roof.ResetCache();
                roof.OnPropertyChangedAfter("Position", null, null);

            }
            else
            {
            }

        }
        public override List<PropertyObserver> GetPropertyObservers()
        {
            //return base.GetPropertyObservers();
            var list = new List<PropertyObserver>() {
             new PropertyObserver()
            {
                Name = "SlabThickness",
                DisplayName = "板厚",
                CategoryName = "Geometry",
                CategoryDisplayName = "几何图形",
                PropType=PropertyType.Double,
                Getter = (ele) => (ele as QdRoofInstance).SlabThickness,
                Setter = (ele, value) =>
                {
                    var roof = (ele as QdRoofInstance);
                    if (!double.TryParse(value.ToString(),out var slabThickness)||slabThickness<0)
                        return;
                    roof.OnPropertyChangedBefore("SlabThickness",roof.Parameters.GetValue<double>("SlabThickness"),slabThickness);
                    roof.Parameters.SetValue("SlabThickness",slabThickness );
                    roof.ResetCache();
                    roof.OnPropertyChangedAfter("SlabThickness",roof.Parameters.GetValue<double>("SlabThickness"),slabThickness);
                }
            },
             new PropertyObserver()
            {
                Name = "FasciaDepth",
                DisplayName = "封檐板厚",
                CategoryName = "Geometry",
                CategoryDisplayName = "几何图形",
                PropType=PropertyType.Double,
                Getter = (ele) => (ele as QdRoofInstance).FasciaDepth,
                Setter = (ele, value) =>
                {
                    var roof = (ele as QdRoofInstance);
                    if (!double.TryParse(value.ToString(),out var fasciaDepth)||fasciaDepth<0)
                        return;
                    roof.OnPropertyChangedBefore("FasciaDepth",roof.Parameters.GetValue<double>("FasciaDepth"),fasciaDepth);
                    roof.Parameters.SetValue("FasciaDepth",fasciaDepth );
                    roof.ResetCache();
                    roof.OnPropertyChangedAfter("FasciaDepth",roof.Parameters.GetValue<double>("FasciaDepth"),fasciaDepth);
                }
            },
              new PropertyObserver()
            {
                Name = "SectionType",
                DisplayName = "橼截面",
                CategoryName = "Geometry",
                CategoryDisplayName = "几何图形",
                PropType = PropertyType.Array,
                Getter = (ele) => QdRoofInstance.SectionEnums[(ele as QdRoofInstance).SectionType],
                Source = (ele) => QdRoofInstance.SectionEnums.Values.ToArray(),
                Setter = (ele, value) =>
                {
                    var roof = (ele as QdRoofInstance);
                    if (!QdRoofInstance.SectionEnums.ContainsValue(value.ToString()))
                        return;
                    var sectionType =QdRoofInstance.SectionEnums.FirstOrDefault(n=>n.Value==value.ToString()).Key;
                    roof.OnPropertyChangedBefore("SectionType",roof.Parameters.GetValue<int>("SectionType"),sectionType);
                    roof.Parameters.SetValue("SectionType",sectionType);
                    roof.ResetCache();
                    roof.OnPropertyChangedAfter("SectionType",roof.Parameters.GetValue<int>("SectionType"),sectionType);
                }
            },  new PropertyObserver()
            {
                Name = "Elevation",
                DisplayName = "标高",
                CategoryName = "Geometry",
                CategoryDisplayName = "几何图形",
                PropType=PropertyType.Double,
                Getter = (ele) => (ele as QdRoofInstance).Elevation,
                Setter = (ele, value) =>
                {
                    var roof = (ele as QdRoofInstance);
                    if (!double.TryParse(value.ToString(),out var elevation)||elevation<0)
                        return;
                    roof.OnPropertyChangedBefore("Elevation",roof.Parameters.GetValue<double>("Elevation"),elevation);
                    roof.Parameters.SetValue("Elevation",elevation );
                    roof.ResetCache();
                    roof.OnPropertyChangedAfter("Elevation",roof.Parameters.GetValue<double>("Elevation"),elevation);
                }
            },
            };
            return list;
        }
 
        #endregion
 
    }
    public class Roof3dAction : ComponentInstance3dAction
    {
        class RoofFace
        {
            public Line2d baseLine;//基线
            public double radian = Math.PI/6;//坡面角度的弧度
            public Vector3 startRay;//基线起点延伸射线法向
            public Vector3 endRay;//基线终点延伸射线法向
            public Vector3 startVertex;//基线起点延伸射线碰撞到其他面最近顶点
            public Vector3 endVertex;//基线终点延伸射线其他面最近顶点
            public RoofFace lastFace;
            public RoofFace nextFace;
            public Vector3 normal;
            public List<Line3d> outloops = new List<Line3d>();
        }

        public override List<Object3D> Render(IComponentInstance cptIns)
        {
            var roof = cptIns as QdRoofInstance;
            var result = new List<Object3D>();
            var lcMats = roof.Definition.Solid3dProvider.AssignMaterialsFunc(cptIns, null);
            var sectionId = roof.Definition.TypeParameters.GetValue<string>("SectionId");
            if (SectionManager.Sections.TryGetValue(sectionId, out var section))
            {
                var roofFaces = section.Segments.Select(n => new RoofFace() { baseLine = (n as Line2d),radian=roof.Angle
                }).ToList() ;
                for (var i=0;i< roofFaces.Count;i++)
                {
                    var face = roofFaces[i];
                    face.lastFace = roofFaces[i - 1 < 0 ? roofFaces.Count - 1 : i - 1];
                    face.nextFace = roofFaces[i + 1 >= roofFaces.Count ? 0 : i + 1];
                    face.normal = new Vector3(0, 0, 1).RotateRoundAxis(new Vector3(), face.baseLine.Dir.ToVector3(), face.radian);
                }
                for (var i = 0; i < roofFaces.Count; i++)
                {
                    var face = roofFaces[i];
                    face.startRay = new Vector3().CrossVectors(face.lastFace.normal, face.normal).Normalize();
                    face.endRay = new Vector3().CrossVectors(face.normal, face.nextFace.normal).Normalize();
                    if (face.startRay.Z < 0)
                    { //内凹面
                        face.startRay.Negate();
                    }
                    if (face.endRay.Z < 0)
                    {
                        face.endRay.Negate();
                    }
                }
                for (var n = 0; n < roofFaces.Count; n++)
                {
                    var currFace = roofFaces[n];
                    for (var m = 0; m < roofFaces.Count; m++)
                    {
                        var otherFace= roofFaces[m];
                        if (otherFace==currFace)
                        {
                            continue;
                        }
                        if(otherFace != currFace.lastFace)
                        {
                            if (IsCollision(currFace.baseLine.Start.ToVector3(),currFace.startRay, otherFace.baseLine.Start.ToVector3(),otherFace.normal,out Vector3 startCp))
                            {
                                var sAngle = startCp.Clone().Sub(otherFace.baseLine.Start.ToVector3()).AngleTo(otherFace.baseLine.Dir.ToVector3());
                                var eAngle = startCp.Clone().Sub(otherFace.baseLine.End.ToVector3()).AngleTo(otherFace.baseLine.Dir.ToVector3());
                                var osAngle = otherFace.startRay.AngleTo(otherFace.baseLine.Dir.ToVector3());
                                var oeAngle = otherFace.endRay.AngleTo(otherFace.baseLine.Dir.ToVector3());
                                if (osAngle - sAngle >= -0.001 && eAngle - oeAngle >= -0.001)
                                {
                                    if (currFace.startVertex == null || currFace.startVertex.DistanceTo(currFace.baseLine.Start.ToVector3()) > startCp.DistanceTo(currFace.baseLine.Start.ToVector3()))
                                    {
                                        currFace.startVertex = startCp;
                                    }
                                }
                            }
                        }
                        if (otherFace != currFace.nextFace)
                        {
                            if (IsCollision(currFace.baseLine.End.ToVector3(), currFace.endRay, otherFace.baseLine.Start.ToVector3(), otherFace.normal, out Vector3 endCp))
                            {
                                var sAngle = endCp.Clone().Sub(otherFace.baseLine.Start.ToVector3()).AngleTo(otherFace.baseLine.Dir.ToVector3());
                                var eAngle = endCp.Clone().Sub(otherFace.baseLine.End.ToVector3()).AngleTo(otherFace.baseLine.Dir.ToVector3());
                                var osAngle = otherFace.startRay.AngleTo(otherFace.baseLine.Dir.ToVector3());
                                var oeAngle = otherFace.endRay.AngleTo(otherFace.baseLine.Dir.ToVector3());
                                if (osAngle - sAngle >= -0.001 && eAngle - oeAngle >= -0.001)
                                {
                                    if (currFace.endVertex == null || currFace.endVertex.DistanceTo(currFace.baseLine.End.ToVector3()) > endCp.DistanceTo(currFace.baseLine.End.ToVector3()))
                                    {
                                        currFace.endVertex = endCp;
                                    }
                                }
                            }
                        }
                    }
                }
                var surfaces = new List<Surface3d>();
                var dbInnerloop = new List<Curve3d>();
                var dbOuterloop = new List<Curve3d>();
                //根据板厚和角度计算屋顶面向下垂直偏移量
                var offsetY = roof.SlabThickness / Math.Cos(roof.Angle);
                ////为双垂直或正方形封橼面时，封檐板深度为0时最大水平向内偏移量
                //var maxHorizontal = roof.SlabThickness / Math.Sin(roof.Angle);
                foreach (var face in roofFaces)
                {
                    var plane = new Plane();
                    plane.SetFromNormalAndCoplanarPoint(face.normal,face.startVertex);
                    var loop = new List<Curve3d>();
                    loop.Add(new Line3d(face.baseLine.Start.ToVector3(),face.baseLine.End.ToVector3()));
                    loop.Add(new Line3d(face.baseLine.End.ToVector3(), face.endVertex.Clone()));
                    getCp(loop,face.nextFace);
                    loop.Add(new Line3d(loop.Last().End.Clone(), face.startVertex.Clone()));
                    loop.Add(new Line3d(face.startVertex.Clone(), face.baseLine.Start.ToVector3()));
                    var planeSurface = new PlanarSurface3d(new Plane(face.normal), loop);
                    surfaces.Add(planeSurface);
                    if (roof.SectionType == 0|| (roof.SectionType == 1&& roof.FasciaDepth >= offsetY))
                    {
                        var bottomSurface = new PlanarSurface3d(new Plane(face.normal.Clone().Negate()), loop.Select(n => n.Clone().Translate(0, 0, -offsetY)).ToList());
                        surfaces.Add(bottomSurface);
                        var connectLoop = new List<Curve3d>();
                        connectLoop.Add(new Line3d(face.baseLine.Start.ToVector3(), face.baseLine.End.ToVector3()));
                        connectLoop.Add(new Line3d(face.baseLine.End.ToVector3(), face.baseLine.End.ToVector3(-offsetY)));
                        connectLoop.Add(new Line3d(face.baseLine.End.ToVector3(-offsetY), face.baseLine.Start.ToVector3(-offsetY)));
                        connectLoop.Add(new Line3d(face.baseLine.Start.ToVector3(-offsetY), face.baseLine.Start.ToVector3()));
                        var connectSurface = new PlanarSurface3d(new Plane(face.baseLine.Dir.ToVector3().Cross(new Vector3(0, 0, 1))), connectLoop);
                        surfaces.Add(bottomSurface);
                        surfaces.Add(connectSurface);
                    }
                    else if(roof.SectionType == 1 && roof.FasciaDepth < offsetY)
                    {
                        var horizontal = (offsetY - roof.FasciaDepth) / Math.Tan(roof.Angle);
                        var offsetL = horizontal / Math.Cos(roof.Angle);
                        var bottomloop = loop.Select(n => n.Clone().Translate(0, 0, - offsetY)).ToList();
                        bottomloop[0].Start.AddScaledVector(face.startRay , offsetL);
                        bottomloop[0].End.AddScaledVector(face.endRay, offsetL);
                        bottomloop[1].Start.AddScaledVector(face.endRay, offsetL);
                        bottomloop[bottomloop.Count-1].End.AddScaledVector(face.startRay, offsetL);
                        var bottomSurface = new PlanarSurface3d(new Plane(face.normal.Clone().Negate()), bottomloop);
                        surfaces.Add(bottomSurface);
                        dbInnerloop.Add(bottomloop[0].Clone());
                        if (roof.FasciaDepth>0)
                        {
                            var connectLoop = new List<Curve3d>();
                            connectLoop.Add(new Line3d(face.baseLine.Start.ToVector3(), face.baseLine.End.ToVector3()));
                            connectLoop.Add(new Line3d(face.baseLine.End.ToVector3(), face.baseLine.End.ToVector3(-roof.FasciaDepth)));
                            connectLoop.Add(new Line3d(face.baseLine.End.ToVector3(-roof.FasciaDepth), face.baseLine.Start.ToVector3(-roof.FasciaDepth)));
                            connectLoop.Add(new Line3d(face.baseLine.Start.ToVector3(-roof.FasciaDepth), face.baseLine.Start.ToVector3()));
                            var connectSurface = new PlanarSurface3d(new Plane(face.baseLine.Dir.ToVector3().Cross(new Vector3(0, 0, 1))), connectLoop);
                            surfaces.Add(connectSurface);
                        }
                    }
                    else if (roof.SectionType == 2)
                    {
                        var fasciaDepth = roof.FasciaDepth > roof.SlabThickness?roof.SlabThickness:roof.FasciaDepth;
                        var offsetL = (offsetY-Math.Cos(roof.Angle)* fasciaDepth) /Math.Sin(roof.Angle);
                        var bottomloop = loop.Select(n => n.Clone().Translate(0, 0, -offsetY)).ToList();
                        bottomloop[0].Start.AddScaledVector(face.startRay, offsetL);
                        bottomloop[0].End.AddScaledVector(face.endRay, offsetL);
                        bottomloop[1].Start.AddScaledVector(face.endRay, offsetL);
                        bottomloop[bottomloop.Count - 1].End.AddScaledVector(face.startRay, offsetL);
                        var bottomSurface = new PlanarSurface3d(new Plane(face.normal.Clone().Negate()), bottomloop);
                        surfaces.Add(bottomSurface);
                        dbInnerloop.Add(bottomloop[0].Clone());
                        if (fasciaDepth > 0)
                        {
                            var osNormal = face.startRay.Clone().RotateRoundAxis(new Vector3(), new Vector3(0, 0, 1).Cross(face.startRay).Normalize(), Math.PI / 2).Normalize();
                            var oeNormal = face.endRay.Clone().RotateRoundAxis(new Vector3(), new Vector3(0, 0, 1).Cross(face.endRay).Normalize(),Math.PI / 2).Normalize();
                            var connectLoop = new List<Curve3d>();
                            connectLoop.Add(new Line3d(face.baseLine.Start.ToVector3(), face.baseLine.End.ToVector3()));
                            connectLoop.Add(new Line3d(face.baseLine.End.ToVector3(), face.baseLine.End.ToVector3().AddScaledVector(oeNormal, fasciaDepth)));
                            connectLoop.Add(new Line3d(face.baseLine.End.ToVector3().AddScaledVector(oeNormal, fasciaDepth), face.baseLine.Start.ToVector3().AddScaledVector(osNormal, roof.FasciaDepth)));
                            connectLoop.Add(new Line3d(face.baseLine.Start.ToVector3().AddScaledVector(osNormal, fasciaDepth), face.baseLine.Start.ToVector3()));
                            var connectSurface = new PlanarSurface3d(new Plane(face.baseLine.Dir.ToVector3().Cross(osNormal).Negate()), connectLoop);
                            surfaces.Add(connectSurface);
                            dbOuterloop.Add(new Line3d(face.baseLine.Start.ToVector3().AddScaledVector(osNormal, fasciaDepth), face.baseLine.End.ToVector3().AddScaledVector(oeNormal, roof.FasciaDepth)));
                        }
                    }

                        //获取连接点
                     void getCp(List<Curve3d> loop, RoofFace next)
                    {
                        if (next.nextFace == face)
                        {
                            return;
                        }
                        else
                        {
                            if (Math.Abs( plane.DistanceToPoint(next.startVertex))<=0.001)
                            {
                                loop.Add(new Line3d(loop.Last().End.Clone(), next.startVertex.Clone()));
                            }
                            getCp(loop, next.nextFace);
                        }
                    }
                }
                if (roof.SectionType == 1 && roof.FasciaDepth < offsetY)
                {
                    var dbSurface = new PlanarSurface3d(new Plane(new Vector3(0, 0, -1)), section.Segments.Select(n=> {
                        var line = n as Line2d;
                        return new Line3d(line.Start.ToVector3(-roof.FasciaDepth),line.End.ToVector3(-roof.FasciaDepth));                   
                    }).ToList<Curve3d>());
                    dbSurface.InnerLoops.Add(dbInnerloop);
                    surfaces.Add(dbSurface);
                }
                if (roof.SectionType == 2 )
                {
                    var dbSurface = new PlanarSurface3d(new Plane(new Vector3(0, 0, -1)), dbOuterloop);
                    dbSurface.InnerLoops.Add(dbInnerloop);
                    surfaces.Add(dbSurface);
                }
                var posArr = new ListEx<double>();
                var idxArr = new ListEx<int>();
                int idxOffset = 0;
                for (int i = 0; i < surfaces.Count; i++)
                {
                    var face = surfaces[i];
                    var tuple = face.Trianglate();
                    idxOffset = posArr.Length / 3;
                    posArr.AddRange(tuple.Item1);
                    idxArr.AddRange(tuple.Item2.Select(idx => idx + idxOffset));
                }
                GeometryData geometryData = new GeometryData();
                geometryData.Position = posArr;
                geometryData.Index = idxArr;
                var geo = geometryData.GetBufferGeometry();
                geo.name = "Roof"; 
                geo.computeVertexNormals();
                geo.SetUV();
                geo.translate(0,0,roof.Elevation);
                var mesh = new Mesh(geo, lcMats.Select(m => RenderMaterialManager.GetRenderMaterial(m.Uuid)).ToArray());
                mesh.position.Set(roof.Transform3d.Position.X, roof.Transform3d.Position.Y, 0);
                result.Add(mesh);
            }
            return result;
        }

        /// <summary>
        /// 射线与平面相交检测
        /// </summary>
        /// <param name="source">射线起点坐标</param>
        /// <param name="rayDirection">射线方向</param>
        /// <param name="planePos">平面上任一点坐标</param>
        /// <param name="planeNormal">平面法向量</param>
        /// <returns></returns>
        public bool IsCollision(Vector3 source, Vector3 rayDirection, Vector3 planePos, Vector3 planeNormal,out Vector3 collisionPosition)
        {
            Vector3 pc = planePos - source;
            double dot_rayDir_planeNormal = rayDirection.Dot(planeNormal);
            double dot_pc_planeNormal = pc.Dot( planeNormal);
            collisionPosition = null;
            // 射线平行于平面
            if (dot_rayDir_planeNormal == 0)
            {
                if (dot_pc_planeNormal == 0)
                {
                    // 射线和平面平行并且射线在平面内
                    return false;
                }
                // 射线和平面平行但是射线不在平面内
                return false;
            }

            if (dot_rayDir_planeNormal > 0 && dot_pc_planeNormal > 0)
            {
                collisionPosition = CollisionPosition(source,  rayDirection,  planePos,  planeNormal);
                return true;
            }

            if (dot_rayDir_planeNormal < 0 && dot_pc_planeNormal < 0)
            {
                collisionPosition = CollisionPosition(source, rayDirection, planePos, planeNormal);
                return true;
            }

            return false;
        }

        public Vector3 CollisionPosition(Vector3 source, Vector3 rayDirection, Vector3 planePos, Vector3 planeNormal)
        {
            double length =(planePos - source).Dot(planeNormal) / rayDirection.Dot( planeNormal);
            return source + rayDirection * length;
        }
 
    }


}
